package net.stuffrepos.bricknetcenter.plugins.peeron;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import net.stuffrepos.bricknetcenter.database.DataManager;
import net.stuffrepos.bricknetcenter.database.DataManager.InformationManager.InformationNode;
import net.stuffrepos.bricknetcenter.database.schema.Information;
import net.stuffrepos.bricknetcenter.http.HttpParser;
import net.stuffrepos.bricknetcenter.http.HttpRequest;
import net.stuffrepos.bricknetcenter.http.HttpResponse;
import net.stuffrepos.bricknetcenter.http.util.HtmlParser;
import net.stuffrepos.bricknetcenter.http.util.LinkPage;
import net.stuffrepos.bricknetcenter.provider.HttpProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;

/**
 * 
 * @author Eduardo H. Bogoni <eduardobogoni@gmail.com>
 */
public class PeeronHttpProvider implements HttpProvider {

    private static final Log log = LogFactory.getLog(PeeronHttpProvider.class);
    private static final String PROVIDER_NAME = "www.peeron.com";
    private static final int SET_LIST_FIRST_PAGE_PRIORITY = Integer.MAX_VALUE;
    private static final int SET_LIST_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 1;
    private static final int SET_DETAIL_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 2;
    private static final int SET_IMAGE_LIST_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 3;
    private static final int SET_IMAGE_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 3;
    private static final int PART_DETAIL_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 3;
    private static final int PART_IMAGE_PRIORITY = SET_LIST_FIRST_PAGE_PRIORITY - 3;
    
    

    private static InformationNode getProviderNode() throws Exception {
        return DataManager.getInstance().getInformationManager().getInformationNode(
                Information.Type.Provider,
                PROVIDER_NAME);
    }

    private static InformationNode getSetsGroup() throws Exception {
        return DataManager.getInstance().getInformationManager().getInformationNode(
                Information.Type.Group,
                "Sets");
    }

    private static InformationNode getPartsGroup() throws Exception {
        return DataManager.getInstance().getInformationManager().getInformationNode(
                Information.Type.Group,
                "Parts");
    }

    @Override
    public Collection<HttpRequest> getRootRequests() {
        List<HttpRequest> list = new LinkedList<HttpRequest>();
        list.add(new SetListFirstPage());
        return list;
    }

    @Override
    public String getName() {
        return PROVIDER_NAME;
    }

    private static class SetListFirstPage implements HttpRequest {

        @Override
        public URL getUrl() {
            try {
                return new URL("http://www.peeron.com/cgi-bin/invcgis/setsearch?PagerSortDir=f&PagerSortCol=ID");
            } catch (MalformedURLException ex) {
                throw new RuntimeException(ex);
            }
        }

        @Override
        public Class<? extends HttpParser> getParserClass() {
            return SetListParser.class;
        }

        @Override
        public Object[] getParserArguments() {
            return new Object[0];
        }

        @Override
        public URL getReferer() {
            try {
                return new URL("http://www.peeron.com");
            } catch (MalformedURLException ex) {
                throw new RuntimeException(ex);
            }
        }

        @Override
        public int getPriority() {
            return SET_LIST_FIRST_PAGE_PRIORITY;
        }

        @Override
        public Method getMethod() {
            return Method.Get;
        }        

        @Override
        public PostParameter[] getPostParameters() {
            return new PostParameter[0];
        }
    }

    public static class SetListParser extends HtmlParser implements HttpParser {

        @Override
        public void parseDocument(HttpResponse response, Document document) throws Exception {
            parsePages(response, document);
            parseSets(response, document);
        }

        private void parsePages(final HttpResponse response, Document document) throws Exception {
            HtmlParser.searchByXpath("/h:html/h:body/h:table[1]/h:tr[1]//h:a/@href", document, new NodeHandler<Attribute>() {

                @Override
                public void handleNode(Attribute node) throws Exception {
                    DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                            new LinkPage(response, node.getValue(), SetListParser.class, SET_LIST_PRIORITY));
                }
            });
        }

        private void parseSets(final HttpResponse response, Document document) throws Exception {
            HtmlParser.searchByXpath("/h:html/h:body/h:table[1]/h:tbody/h:tr", document, new NodeHandler<Element>() {

                @Override
                public void handleNode(Element node) throws Exception {
                    Element setLink = (Element) HtmlParser.uniqueNode("h:td[1]/h:a", node);
                    Element nameCell = (Element) HtmlParser.uniqueNode("h:td[2]", node);
                    Element themeCell = (Element) HtmlParser.uniqueNode("h:td[3]", node);
                    Element yearCell = (Element) HtmlParser.uniqueNode("h:td[4]", node);
                    Element partsCell = (Element) HtmlParser.uniqueNode("h:td[5]", node);
                    Element minifigsCell = (Element) HtmlParser.uniqueNode("h:td[6]", node);

                    DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                            new LinkPage(response, setLink.getAttributeValue("href"), SetDetailParser.class, SET_DETAIL_PRIORITY));

                    getSetsGroup().
                            addChild(Information.Type.Set, setLink.getTextNormalize()).
                            getChildren().
                            addNode(Information.Type.Name, nameCell.getTextNormalize()).
                            addNode(Information.Type.Theme, themeCell.getTextNormalize()).
                            addNode(Information.Type.Parts, partsCell.getTextNormalize()).
                            addNode(Information.Type.Year, yearCell.getTextNormalize()).
                            addNode(Information.Type.Minifigs, minifigsCell.getTextNormalize());
                }
            });
        }
    }

    public static class SetDetailParser extends HtmlParser implements HttpParser {

        @Override
        public void parseDocument(HttpResponse response, Document document) throws Exception {
            parseParts(response, document, getSetNumber(response));
            parseImages(response, document, getSetNumber(response));
        }

        public String getSetNumber(HttpResponse response) {
            String[] parts = response.getUrl().getPath().split("/");
            return parts[parts.length - 1];
        }

        private void parseParts(final HttpResponse response, Document document, final String setNumber) throws Exception {
            HtmlParser.searchByXpath("/h:html/h:body/h:table[2]/h:tbody/h:tr", document, new HtmlParser.NodeHandler<Element>() {

                @Override
                public void handleNode(Element node) throws Exception {
                    Element quantityCell = (Element) HtmlParser.uniqueNode("h:td[1]", node);
                    Element numberLink = (Element) HtmlParser.uniqueNode("h:td[2]/h:a", node);
                    Element colorCell = (Element) HtmlParser.uniqueNode("h:td[3]", node);
                    Element nameCell = (Element) HtmlParser.uniqueNode("h:td[4]", node);
                    //Element imageCell = (Element) HtmlParser.uniqueNode("h:td[5]", node);
                    Element noteCell = (Element) HtmlParser.uniqueNode("h:td[6]", node);

                    DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                            new LinkPage(response, numberLink.getAttributeValue("href"), PartDetailParser.class, PART_DETAIL_PRIORITY));

                    getPartsGroup().
                            addChild(Information.Type.Part, numberLink.getTextNormalize()).
                            addChild(Information.Type.Name, nameCell.getTextNormalize());

                    getSetsGroup().
                            addChild(Information.Type.Set, setNumber).
                            addChild(Information.Type.SetPart, numberLink.getTextNormalize()).
                            addChild(Information.Type.Color, colorCell.getTextNormalize()).
                            getChildren().
                            addNode(Information.Type.Quantity, Integer.parseInt(quantityCell.getTextNormalize())).
                            addNode(Information.Type.Note, noteCell.getTextNormalize());

                }
            });
        }

        private void parseImages(final HttpResponse response, Document document, String setNumber) throws Exception {
            HtmlParser.searchByXpath("/h:html/h:body/h:table[1]//h:table[1]//h:a", document, new NodeHandler<Element>() {

                @Override
                public void handleNode(Element node) throws Exception {
                    DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                            new LinkPage(response, node.getAttributeValue("href"), SetImageListParser.class, SET_IMAGE_LIST_PRIORITY));
                }
            });
        }
    }

    public static class SetImageListParser extends HtmlParser implements HttpParser {

        @Override
        public void parseDocument(HttpResponse response, Document document) throws Exception {
            Element image = (Element) HtmlParser.uniqueNode("/h:html/h:body/h:table[2]//h:img[1]", document);
            DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                    new LinkPage(response, image.getAttributeValue("src"), SetImageParser.class, SET_IMAGE_PRIORITY));
        }
    }

    public static class SetImageParser implements HttpParser {

        private String getSetNumber(HttpResponse response) {
            String[] urlParts = response.getUrl().getPath().split("/");
            String[] nameParts = urlParts[urlParts.length - 1].split("\\.");
            return nameParts[0];
        }

        private String getImageName(HttpResponse response) {
            String[] parts = response.getUrl().getPath().split("/");
            return parts[parts.length - 1];
        }

        private String getMimeType(HttpResponse response) {
            return response.getMimeType();
        }

        @Override
        public void parse(HttpResponse response) throws Exception {
            getSetsGroup().
                    addChild(Information.Type.Set, getSetNumber(response)).
                    addBlobChild(
                    Information.Type.Image,
                    getImageName(response),
                    getMimeType(response),
                    response.getInputStream());
        }
    }

    public static class PartDetailParser extends HtmlParser implements HttpParser {

        @Override
        public void parseDocument(HttpResponse response, Document document) throws Exception {
            Element zoomImageLink = (Element) HtmlParser.uniqueNode("/h:html/h:body/h:table[1]//h:table[1]//h:a[1]", document);

            DataManager.getInstance().getHttpRequestManager().addHttpRequest(
                    new LinkPage(response, zoomImageLink.getAttributeValue("href"), PartImageParser.class, PART_IMAGE_PRIORITY));
        }
    }

    public static class PartImageParser implements HttpParser {

        private String getImageName(HttpResponse response) {
            String[] parts = response.getUrl().getPath().split("/");
            return parts[parts.length - 1];
        }

        private String getMimeType(HttpResponse response) {
            return response.getMimeType();
        }

        @Override
        public void parse(HttpResponse response) throws Exception {
            getPartsGroup().
                    addChild(Information.Type.Part, getPartNumber(response)).
                    addBlobChild(
                    Information.Type.Image,
                    getImageName(response),
                    getMimeType(response),
                    response.getInputStream());
        }

        private String getPartNumber(HttpResponse response) {
            String[] urlParts = response.getUrl().getPath().split("/");
            String[] nameParts = urlParts[urlParts.length - 1].split("\\.");
            return nameParts[0];
        }
    }
}
